<?php

namespace Sharks\Core\LifeCycle;

use Closure;
use ReflectionMethod;
use Sharks\Core\AppContext;
use Sharks\Core\Cfg\AppConfig;
use Sharks\Core\Exception\RouteResolveException;
use Sharks\Core\Http\Request;
use Sharks\Core\Http\Response;
use Sharks\Core\Http\Routing\FormCsrfMiddleWare;
use Sharks\Core\Support\Log\Log;

class ActionPiple {

	public function __construct() {
        $resolvers = ResolverLoader::load(
            array(RouteParamResolver::class, DefaultParamResolver::class, RequestParamResolver::class));
        foreach ($resolvers as $resolver) {
            ActionParamResolver::register($resolver);
        }
	}

	public function line(Request $request, Response $response) {
        Event::fire('lining', $this);
        $routeResult = $request->route;
        require_once (__DIR__ . '/../Http/View/Render.php');
        if (false == $routeResult->isHit) {
            $response->status(404);
            throw new RouteResolveException('没有找到匹配的route');
        }
        else {
            $view = $this->doMiddleWaves($request, $response);
            $response->setView($view);
        }
        Event::fire('lined', $this);
	}

	/**
     * 中间件执行
     */
    public function doMiddleWaves(Request $request, Response $response) {
        $routeResult = $request->route;

        if (count($routeResult->middlewares) > 0) {

            $middlewares = $routeResult->middlewareObjs;

            // add csrf check for POST
            if ($request->isPost()) {
//                array_unshift($middlewares, new FormCsrfMiddleWare());
            }

            $n = null;
            $next = function(Request $request, Closure &$_closure = null) use(&$middlewares, &$n, $response) {

                if (empty($middlewares)) {
                    return $this->action($request, $response);
                }
                $middleware = array_shift($middlewares);

                if (is_null($n)) {
                    $n = $_closure;
                }
                return $middleware->handle($request, $n);
            };

            return $next($request, $next);
        }
        else {
            return $this->action($request, $response);
        }
    }

    protected function action($request, $response) {
        $v = $this->doPreAction($request, $response);

        if (!is_null($v)) {
            return $v;
        }
        return $this->doAction($request, $response);
    }

    public function doPreAction($request, $response) {
        $routeResult = $request->route;

        if (method_exists($routeResult->controllerObj, '_' . $routeResult->method)) {
            $method = new ReflectionMethod($routeResult->controllerObj, '_' . $routeResult->method);

            return $this->invoke($method, $routeResult);
        }
    }

    /**
     * action执行
     */
    public function doAction($request, $response) {
        $routeResult = $request->route;
        $method = new ReflectionMethod($routeResult->controllerObj, $routeResult->method);
        return $this->invoke($method, $routeResult);
    }

    protected function invoke($method, $route) {
        $paramContainer = array();

        foreach ($method->getParameters() as $param) {
            $name = $param->getName();
            $type = is_null($param->getClass()) ? null : $param->getClass()->getName();
        	$p = ActionParamResolver::get($name, $type);

        	if ($p == null && $param->isDefaultValueAvailable()) {
        		$p = $param->getDefaultValue();
        	}
            $paramContainer[] = $p;
        }

        if (empty($paramContainer)) {
            $view = $method->invoke($route->controllerObj);
        }
        else {
            $view = $method->invokeArgs($route->controllerObj, $paramContainer);
        }
        if (!is_null($view)) {
            return $view;
        }
    }
}
